//
//  Sprite.m
//  MapEdit
//
//  Created by Steven Canfield on 26/06/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "Sprite.h"

@implementation Sprite
static PCXFile * playerPalette = NULL;
static ColorPalette * colorPalette = NULL;

+ (void)setUnitPalette:(ColorPalette *)cp {
	colorPalette = cp;
}

+ (void)setPlayerPalette:(PCXFile *)pp {
	playerPalette = pp;
}

- (id)initWithData:(NSData *)data {
	self = [super init];
	if( self ) {
		grpData = [data retain];
		bitmaps = malloc( (sizeof(NSMutableArray *) * NUM_COLORS));
		int playerIndex = 0;
		for( playerIndex = 0; playerIndex < NUM_COLORS; playerIndex++ ) {
			//[bitmaps addObject:[NSMutableArray array]];
			bitmaps[ playerIndex ] = NULL;
		}

	}
	return self;
}

- (void)_loadSpriteForPlayerColor:(int)playerColor {

	bitmaps[playerColor] = [[NSMutableArray alloc] init];
	int dataIndex = 0;
	[grpData getBytes:&frameCount range:NSMakeRange( dataIndex, sizeof( u_int16_t ))];
	frameCount = NSSwapLittleShortToHost( frameCount );
	dataIndex += sizeof( u_int16_t );

	NSDate * then = [NSDate date];
	
	[grpData getBytes:&boundsWidth range:NSMakeRange( dataIndex, sizeof( u_int16_t ))];
	boundsWidth = NSSwapLittleShortToHost( boundsWidth );
	dataIndex += sizeof( u_int16_t );

	[grpData getBytes:&boundsHeight range:NSMakeRange( dataIndex, sizeof( u_int16_t ))];
	boundsHeight = NSSwapLittleShortToHost( boundsHeight );
	dataIndex += sizeof( u_int16_t );
			
	/* Reading Frame Info */
	int frameInfoIndex = 0;
	u_int32_t	frameDataOffset[ frameCount ];
	offsetX = malloc( sizeof( u_int8_t ) * frameCount);
	offsetY = malloc( sizeof( u_int8_t ) * frameCount);

	
	frameWidth = malloc( sizeof( u_int8_t ) * frameCount);
	frameHeight = malloc( sizeof( u_int8_t ) * frameCount);
	
	for( frameInfoIndex = 0; frameInfoIndex < frameCount; frameInfoIndex++ )  {
		[grpData getBytes:&offsetX[ frameInfoIndex ] range:NSMakeRange( dataIndex, sizeof( u_int8_t ))];
		dataIndex += sizeof( u_int8_t );
		
		[grpData getBytes:&offsetY[ frameInfoIndex ] range:NSMakeRange( dataIndex, sizeof( u_int8_t ))];
		dataIndex += sizeof( u_int8_t );
					
		[grpData getBytes:&frameWidth[ frameInfoIndex ] range:NSMakeRange( dataIndex, sizeof( u_int8_t ))];
		dataIndex += sizeof( u_int8_t );

		[grpData getBytes:&frameHeight[ frameInfoIndex ] range:NSMakeRange( dataIndex, sizeof( u_int8_t ))];
		dataIndex += sizeof( u_int8_t );
		
		[grpData getBytes:&frameDataOffset[ frameInfoIndex ] range:NSMakeRange( dataIndex , sizeof( u_int32_t ))];
		frameDataOffset[ frameInfoIndex ] = NSSwapLittleIntToHost( frameDataOffset[ frameInfoIndex ] );
		dataIndex += sizeof( u_int32_t );
	}
			
	for( frameInfoIndex = 0; frameInfoIndex < 1; frameInfoIndex++ ) {
		NSImage * image = [[NSImage alloc] initWithSize:NSMakeSize( boundsWidth, boundsHeight )];
		[image lockFocus];
		NSBitmapImageRep * coloredRep = [NSBitmapImageRep imageRepWithData:[ image TIFFRepresentation ]];
		[image unlockFocus];
		
		dataIndex = frameDataOffset[ frameInfoIndex ];
		int topOfFrameIndex = dataIndex;

		u_int16_t firstLineOffset;
		[grpData getBytes:&firstLineOffset range:NSMakeRange( dataIndex, sizeof( u_int16_t ))];
		firstLineOffset = NSSwapLittleShortToHost( firstLineOffset );
		int numLines = firstLineOffset / 2;
		
		u_int16_t lineOffset[ numLines ];
		
		int lineIndex;
		for( lineIndex = 0; lineIndex < numLines; lineIndex++ ) {
			[grpData getBytes:&lineOffset[ lineIndex ] range:NSMakeRange( dataIndex , sizeof( u_int16_t ))];
			lineOffset[ lineIndex ] = NSSwapLittleShortToHost( lineOffset[ lineIndex ]);
			dataIndex += sizeof( u_int16_t );
		}
					
		for( lineIndex = 0; lineIndex < numLines; lineIndex++ ) {
			dataIndex = topOfFrameIndex + lineOffset[ lineIndex ];
			
			int X;
			if( lineIndex == 0 ) {
				X = frameWidth[ frameInfoIndex ] - offsetX[ frameInfoIndex ];
			} else {
				X = frameWidth[ frameInfoIndex ];
			}
			
			while( dataIndex < [grpData length] && X > 0) {
				u_int8_t byte;
				[grpData getBytes:&byte range:NSMakeRange( dataIndex, sizeof( u_int8_t ))];
				dataIndex += sizeof( u_int8_t );
				
				if( byte > 0x80 ) {
					byte -= 0x80;
					while( byte-- && X > 0) {
						X--;
					}
				} else if ( byte > 0x40 ) {
					int numTimesToCopy = byte - 0x40;
					/* Grab Next Byte */
					[grpData getBytes:&byte range:NSMakeRange( dataIndex, sizeof( u_int8_t ))];
					dataIndex += sizeof( u_int8_t );
					while( numTimesToCopy-- && X > 0) {
							if( byte >= 8 && byte <= 15) {
								unsigned int * pixel = [playerPalette pixelAtX:playerColor * 8 + (byte-8) Y:0];
								[coloredRep setPixel:pixel atX:(boundsWidth - X) y:(lineIndex + offsetY[ frameInfoIndex ])];
								free( pixel );
							} else {
								unsigned int * pixel = [colorPalette pixelAtIndex:byte];
								[coloredRep setPixel:pixel atX:(boundsWidth - X) y:(lineIndex + offsetY[ frameInfoIndex ])];
								free( pixel );
							}
						X--;
					}
				} else if( byte < 0x40 ) {
					int numBytesToCopy = byte;
					/* copy next numBytesToCopy to image */						
					while( numBytesToCopy-- && X > 0 ) {
						[grpData getBytes:&byte range:NSMakeRange( dataIndex, sizeof( u_int8_t ))];
						dataIndex += sizeof( u_int8_t );
							if( byte >= 8 && byte <= 15) {
								unsigned int * pixel = [playerPalette pixelAtX:playerColor * 8 + (byte-8) Y:0];
								[coloredRep setPixel:pixel atX:(boundsWidth - X) y:(lineIndex + offsetY[ frameInfoIndex ])];
								free( pixel );
							} else {
								unsigned int * pixel = [colorPalette pixelAtIndex:byte];
								[coloredRep setPixel:pixel atX:(boundsWidth - X) y:(lineIndex + offsetY[ frameInfoIndex ])];
								free( pixel );
							}
						X--;
					}
				}
			}
			
		[bitmaps[playerColor] addObject:coloredRep];
		}
	}
	
	NSDate * now = [NSDate date];
	NSLog(@"%i frames, %f ms", frameCount, [now timeIntervalSinceDate:then] * 1000 );
}

- (NSBitmapImageRep *)frameAtIndex:(int)index owner:(int)colorIndex {
	if( colorIndex >= NUM_COLORS ) {
		colorIndex = 0;
	}
	if( bitmaps[colorIndex] == NULL ) {
		//NSLog(@"Loading player color %i", colorIndex );
		[self _loadSpriteForPlayerColor:colorIndex];
		BOOL fullyLoaded = YES;
		int i = 0;
		for( i = 0; i < NUM_COLORS; i++ ) {
			if( bitmaps[i] == NULL ) {
				fullyLoaded = NO;
			}
		}
		if( fullyLoaded ) {
			[grpData release];
		}
	}
	NSArray * framesForPlayer = bitmaps[colorIndex];
	if( index >= [framesForPlayer count] ) {
		index = 0;
	}
	return [framesForPlayer objectAtIndex:index];	
}



- (int)boundingWidth {
	return boundsWidth;
}
- (int)boundingHeight {
	return boundsHeight;
}

- (int)widthForFrame:(int)index {
	return frameWidth[index];
}
- (int)heightForFrame:(int)index {
	return frameHeight[index];
}

- (int)horizOffsetForFrame:(int)index {
	return offsetX[ index ];
}

- (int)verticalOffsetForFrame:(int)index {
	return offsetY[ index ];
}

- (int)frameCount {
	return frameCount;
}

- (BOOL)hitTest:(NSPoint)point {
	NSBitmapImageRep * imageRep = [self frameAtIndex:0 owner:2];
	if( [[imageRep colorAtX:(int)point.x y:(int)point.y] alphaComponent] != 1.0 ) {
		//NSLog( NSStringFromPoint( point ));
		//NSLog( [[imageRep colorAtX:point.x y:point.y] description]);
		return NO;
	}
	return YES;
}

- (void)dealloc {
	int bitmapIndex = 0;
	for( bitmapIndex = 0; bitmapIndex < NUM_COLORS; bitmapIndex++ ) {
		if( bitmaps[ bitmapIndex ] != NULL ) {
			[bitmaps[ bitmapIndex ] release];
			bitmaps[bitmapIndex] = NULL;
		}
	}
	free( offsetX );
	free( offsetY );
	free( frameHeight );
	free( frameWidth );
	[super dealloc];
}
@end
